﻿namespace com.game.Public.PoolManager
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using UnityEngine;

    [Serializable]
    public class PrefabPool
    {
        internal List<Transform> _despawned;
        public bool _logMessages;
        private bool _preloaded;
        internal List<Transform> _spawned;
        public int cullAbove;
        public int cullDelay;
        public bool cullDespawned;
        private bool cullingActive;
        public int cullMaxPerPass;
        private bool forceLoggingSilent;
        public int limitAmount;
        public bool limitFIFO;
        public bool limitInstances;
        public Transform prefab;
        internal GameObject prefabGO;
        public int preloadAmount;
        public float preloadDelay;
        public int preloadFrames;
        public bool preloadTime;
        public SpawnPool spawnPool;

        public PrefabPool()
        {
            this.preloadAmount = 1;
            this.preloadFrames = 2;
            this.limitAmount = 100;
            this.cullAbove = 50;
            this.cullDelay = 60;
            this.cullMaxPerPass = 5;
            this._spawned = new List<Transform>();
            this._despawned = new List<Transform>();
        }

        public PrefabPool(Transform prefab)
        {
            this.preloadAmount = 1;
            this.preloadFrames = 2;
            this.limitAmount = 100;
            this.cullAbove = 50;
            this.cullDelay = 60;
            this.cullMaxPerPass = 5;
            this._spawned = new List<Transform>();
            this._despawned = new List<Transform>();
            this.prefab = prefab;
            this.prefabGO = prefab.gameObject;
        }

        internal void AddUnpooled(Transform inst, bool despawn)
        {
            this.nameInstance(inst);
            if (despawn)
            {
                PoolManagerUtils.SetActive(inst.gameObject, false);
                this._despawned.Add(inst);
            }
            else
            {
                this._spawned.Add(inst);
            }
        }

        [DebuggerHidden]
        internal IEnumerator CullDespawned()
        {
            return new <CullDespawned>c__Iterator1D { <>f__this = this };
        }

        internal bool DespawnInstance(Transform xform)
        {
            return this.DespawnInstance(xform, true);
        }

        internal bool DespawnInstance(Transform xform, bool sendEventMessage)
        {
            if (this.logMessages)
            {
                UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): Despawning '{2}'", this.spawnPool.poolName, this.prefab.name, xform.name));
            }
            this._spawned.Remove(xform);
            this._despawned.Add(xform);
            if (sendEventMessage)
            {
                xform.gameObject.BroadcastMessage("OnDespawned", SendMessageOptions.DontRequireReceiver);
            }
            PoolManagerUtils.SetActive(xform.gameObject, false);
            if ((!this.cullingActive && this.cullDespawned) && (this.totalCount > this.cullAbove))
            {
                this.cullingActive = true;
                this.spawnPool.StartCoroutine(this.CullDespawned());
            }
            return true;
        }

        internal void inspectorInstanceConstructor()
        {
            this.prefabGO = this.prefab.gameObject;
            this._spawned = new List<Transform>();
            this._despawned = new List<Transform>();
        }

        private void nameInstance(Transform instance)
        {
            instance.name = instance.name + ((this.totalCount + 1)).ToString("#000");
        }

        internal void PreloadInstances()
        {
            if (this.preloaded)
            {
                UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): Already preloaded! You cannot preload twice. If you are running this through code, make sure it isn't also defined in the Inspector.", this.spawnPool.poolName, this.prefab.name));
            }
            else if (this.prefab == null)
            {
                UnityEngine.Debug.LogError(string.Format("SpawnPool {0} ({1}): Prefab cannot be null.", this.spawnPool.poolName, this.prefab.name));
            }
            else
            {
                if (this.limitInstances && (this.preloadAmount > this.limitAmount))
                {
                    UnityEngine.Debug.LogWarning(string.Format("SpawnPool {0} ({1}): You turned ON 'Limit Instances' and entered a 'Limit Amount' greater than the 'Preload Amount'! Setting preload amount to limit amount.", this.spawnPool.poolName, this.prefab.name));
                    this.preloadAmount = this.limitAmount;
                }
                if (this.cullDespawned && (this.preloadAmount > this.cullAbove))
                {
                    UnityEngine.Debug.LogWarning(string.Format("SpawnPool {0} ({1}): You turned ON Culling and entered a 'Cull Above' threshold greater than the 'Preload Amount'! This will cause the culling feature to trigger immediatly, which is wrong conceptually. Only use culling for extreme situations. See the docs.", this.spawnPool.poolName, this.prefab.name));
                }
                if (this.preloadTime)
                {
                    if (this.preloadFrames > this.preloadAmount)
                    {
                        UnityEngine.Debug.LogWarning(string.Format("SpawnPool {0} ({1}): Preloading over-time is on but the frame duration is greater than the number of instances to preload. The minimum spawned per frame is 1, so the maximum time is the same as the number of instances. Changing the preloadFrames value...", this.spawnPool.poolName, this.prefab.name));
                        this.preloadFrames = this.preloadAmount;
                    }
                    this.spawnPool.StartCoroutine(this.PreloadOverTime());
                }
                else
                {
                    this.forceLoggingSilent = true;
                    while (this.totalCount < this.preloadAmount)
                    {
                        Transform xform = this.SpawnNew();
                        this.DespawnInstance(xform, false);
                    }
                    this.forceLoggingSilent = false;
                }
            }
        }

        [DebuggerHidden]
        private IEnumerator PreloadOverTime()
        {
            return new <PreloadOverTime>c__Iterator1E { <>f__this = this };
        }

        internal void SelfDestruct()
        {
            this.prefab = null;
            this.prefabGO = null;
            this.spawnPool = null;
            foreach (Transform transform in this._despawned)
            {
                if (transform != null)
                {
                    UnityEngine.Object.Destroy(transform.gameObject);
                }
            }
            foreach (Transform transform2 in this._spawned)
            {
                if (transform2 != null)
                {
                    UnityEngine.Object.Destroy(transform2.gameObject);
                }
            }
            this._spawned.Clear();
            this._despawned.Clear();
        }

        private void SetRecursively(Transform xform, int layer)
        {
            xform.gameObject.layer = layer;
            IEnumerator enumerator = xform.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    Transform current = (Transform) enumerator.Current;
                    this.SetRecursively(current, layer);
                }
            }
            finally
            {
                IDisposable disposable = enumerator as IDisposable;
                if (disposable == null)
                {
                }
                disposable.Dispose();
            }
        }

        internal Transform SpawnInstance(Vector3 pos, Quaternion rot)
        {
            Transform transform2;
            if ((this.limitInstances && this.limitFIFO) && (this._spawned.Count >= this.limitAmount))
            {
                Transform transform = this._spawned[0];
                if (this.logMessages)
                {
                    UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): LIMIT REACHED! FIFO=True. Calling despawning for {2}...", this.spawnPool.poolName, this.prefab.name, transform));
                }
                this.DespawnInstance(transform);
                this.spawnPool._spawned.Remove(transform);
            }
            if (this._despawned.Count == 0)
            {
                transform2 = this.SpawnNew(pos, rot);
            }
            else
            {
                transform2 = this._despawned[0];
                this._despawned.RemoveAt(0);
                this._spawned.Add(transform2);
                if (transform2 == null)
                {
                    string message = "Make sure you didn't delete a despawned instance directly.";
                    throw new MissingReferenceException(message);
                }
                if (this.logMessages)
                {
                    UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): respawning '{2}'.", this.spawnPool.poolName, this.prefab.name, transform2.name));
                }
                transform2.position = pos;
                transform2.rotation = rot;
                PoolManagerUtils.SetActive(transform2.gameObject, true);
            }
            if (transform2 != null)
            {
                transform2.gameObject.BroadcastMessage("OnSpawned", SendMessageOptions.DontRequireReceiver);
            }
            return transform2;
        }

        public Transform SpawnNew()
        {
            return this.SpawnNew(Vector3.zero, Quaternion.identity);
        }

        public Transform SpawnNew(Vector3 pos, Quaternion rot)
        {
            if (this.limitInstances && (this.totalCount >= this.limitAmount))
            {
                if (this.logMessages)
                {
                    UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): LIMIT REACHED! Not creating new instances! (Returning null)", this.spawnPool.poolName, this.prefab.name));
                }
                return null;
            }
            if (pos == Vector3.zero)
            {
                pos = this.spawnPool.group.position;
            }
            if (rot == Quaternion.identity)
            {
                rot = this.spawnPool.group.rotation;
            }
            Transform instance = (Transform) UnityEngine.Object.Instantiate(this.prefab, pos, rot);
            this.nameInstance(instance);
            if (!this.spawnPool.dontReparent)
            {
                instance.parent = this.spawnPool.group;
            }
            if (this.spawnPool.matchPoolScale)
            {
                instance.localScale = Vector3.one;
            }
            if (this.spawnPool.matchPoolLayer)
            {
                this.SetRecursively(instance, this.spawnPool.gameObject.layer);
            }
            this._spawned.Add(instance);
            if (this.logMessages)
            {
                UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): Spawned new instance '{2}'.", this.spawnPool.poolName, this.prefab.name, instance.name));
            }
            return instance;
        }

        public List<Transform> despawned
        {
            get
            {
                return new List<Transform>(this._despawned);
            }
        }

        public bool logMessages
        {
            get
            {
                if (this.forceLoggingSilent)
                {
                    return false;
                }
                if (this.spawnPool.logMessages)
                {
                    return this.spawnPool.logMessages;
                }
                return this._logMessages;
            }
        }

        internal bool preloaded
        {
            get
            {
                return this._preloaded;
            }
            private set
            {
                this._preloaded = value;
            }
        }

        public List<Transform> spawned
        {
            get
            {
                return new List<Transform>(this._spawned);
            }
        }

        public int totalCount
        {
            get
            {
                int num = 0;
                num += this._spawned.Count;
                return (num + this._despawned.Count);
            }
        }

        [CompilerGenerated]
        private sealed class <CullDespawned>c__Iterator1D : IEnumerator, IDisposable, IEnumerator<object>
        {
            internal object $current;
            internal int $PC;
            internal PrefabPool <>f__this;
            internal int <i>__0;
            internal Transform <inst>__1;

            [DebuggerHidden]
            public void Dispose()
            {
                this.$PC = -1;
            }

            public bool MoveNext()
            {
                uint num = (uint) this.$PC;
                this.$PC = -1;
                switch (num)
                {
                    case 0:
                        if (this.<>f__this.logMessages)
                        {
                            UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): CULLING TRIGGERED! Waiting {2}sec to begin checking for despawns...", this.<>f__this.spawnPool.poolName, this.<>f__this.prefab.name, this.<>f__this.cullDelay));
                        }
                        this.$current = new WaitForSeconds((float) this.<>f__this.cullDelay);
                        this.$PC = 1;
                        goto Label_02AD;

                    case 1:
                    case 2:
                        if (this.<>f__this.totalCount > this.<>f__this.cullAbove)
                        {
                            this.<i>__0 = 0;
                            while (this.<i>__0 < this.<>f__this.cullMaxPerPass)
                            {
                                if (this.<>f__this.totalCount <= this.<>f__this.cullAbove)
                                {
                                    break;
                                }
                                if (this.<>f__this._despawned.Count > 0)
                                {
                                    this.<inst>__1 = this.<>f__this._despawned[0];
                                    this.<>f__this._despawned.RemoveAt(0);
                                    UnityEngine.Object.Destroy(this.<inst>__1.gameObject);
                                    if (this.<>f__this.logMessages)
                                    {
                                        object[] args = new object[] { this.<>f__this.spawnPool.poolName, this.<>f__this.prefab.name, this.<>f__this.cullAbove, this.<>f__this.totalCount };
                                        UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): CULLING to {2} instances. Now at {3}.", args));
                                    }
                                }
                                else if (this.<>f__this.logMessages)
                                {
                                    UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): CULLING waiting for despawn. Checking again in {2}sec", this.<>f__this.spawnPool.poolName, this.<>f__this.prefab.name, this.<>f__this.cullDelay));
                                    break;
                                }
                                this.<i>__0++;
                            }
                            break;
                        }
                        if (this.<>f__this.logMessages)
                        {
                            UnityEngine.Debug.Log(string.Format("SpawnPool {0} ({1}): CULLING FINISHED! Stopping", this.<>f__this.spawnPool.poolName, this.<>f__this.prefab.name));
                        }
                        this.<>f__this.cullingActive = false;
                        this.$current = null;
                        this.$PC = 3;
                        goto Label_02AD;

                    case 3:
                        this.$PC = -1;
                        goto Label_02AB;

                    default:
                        goto Label_02AB;
                }
                this.$current = new WaitForSeconds((float) this.<>f__this.cullDelay);
                this.$PC = 2;
                goto Label_02AD;
            Label_02AB:
                return false;
            Label_02AD:
                return true;
            }

            [DebuggerHidden]
            public void Reset()
            {
                throw new NotSupportedException();
            }

            object IEnumerator<object>.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.$current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.$current;
                }
            }
        }

        [CompilerGenerated]
        private sealed class <PreloadOverTime>c__Iterator1E : IEnumerator, IDisposable, IEnumerator<object>
        {
            internal object $current;
            internal int $PC;
            internal PrefabPool <>f__this;
            internal int <amount>__0;
            internal int <i>__3;
            internal Transform <inst>__6;
            internal int <n>__5;
            internal int <numPerFrame>__2;
            internal int <numThisFrame>__4;
            internal int <remainder>__1;

            [DebuggerHidden]
            public void Dispose()
            {
                this.$PC = -1;
            }

            public bool MoveNext()
            {
                uint num = (uint) this.$PC;
                this.$PC = -1;
                switch (num)
                {
                    case 0:
                        this.$current = new WaitForSeconds(this.<>f__this.preloadDelay);
                        this.$PC = 1;
                        goto Label_01C0;

                    case 1:
                        this.<amount>__0 = this.<>f__this.preloadAmount - this.<>f__this.totalCount;
                        if (this.<amount>__0 > 0)
                        {
                            this.<remainder>__1 = this.<amount>__0 % this.<>f__this.preloadFrames;
                            this.<numPerFrame>__2 = this.<amount>__0 / this.<>f__this.preloadFrames;
                            this.<>f__this.forceLoggingSilent = true;
                            this.<i>__3 = 0;
                            while (this.<i>__3 < this.<>f__this.preloadFrames)
                            {
                                this.<numThisFrame>__4 = this.<numPerFrame>__2;
                                if (this.<i>__3 == (this.<>f__this.preloadFrames - 1))
                                {
                                    this.<numThisFrame>__4 += this.<remainder>__1;
                                }
                                this.<n>__5 = 0;
                                while (this.<n>__5 < this.<numThisFrame>__4)
                                {
                                    this.<inst>__6 = this.<>f__this.SpawnNew();
                                    if (this.<inst>__6 != null)
                                    {
                                        this.<>f__this.DespawnInstance(this.<inst>__6, false);
                                    }
                                    this.$current = null;
                                    this.$PC = 2;
                                    goto Label_01C0;
                                Label_0148:
                                    this.<n>__5++;
                                }
                                if (this.<>f__this.totalCount > this.<>f__this.preloadAmount)
                                {
                                    break;
                                }
                                this.<i>__3++;
                            }
                            break;
                        }
                        goto Label_01BE;

                    case 2:
                        goto Label_0148;

                    default:
                        goto Label_01BE;
                }
                this.<>f__this.forceLoggingSilent = false;
                this.$PC = -1;
            Label_01BE:
                return false;
            Label_01C0:
                return true;
            }

            [DebuggerHidden]
            public void Reset()
            {
                throw new NotSupportedException();
            }

            object IEnumerator<object>.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.$current;
                }
            }

            object IEnumerator.Current
            {
                [DebuggerHidden]
                get
                {
                    return this.$current;
                }
            }
        }
    }
}

